package com.zz.springboot.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.zz.springboot.constant.PathConstants;
import com.zz.springboot.constant.TypeConstants;
import com.zz.springboot.dto.DataDTO;
import com.zz.springboot.resp.enums.RespCodeEnum;
import com.zz.springboot.exception.BizException;
import com.zz.springboot.listener.ImportExcelListener;
import com.zz.springboot.manager.*;
import com.zz.springboot.model.*;
import com.zz.springboot.service.ExcelDealService;
import com.zz.springboot.service.GenerateService;
import com.zz.springboot.util.CloneUtils;
import com.zz.springboot.util.NumParseUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service
@Slf4j
public class ExcelDealServiceImpl implements ExcelDealService {

    @Autowired
    AoMenManager aoMenManager;

    @Autowired
    XiangGangManager xiangGangManager;

    @Autowired
    ExcelDealManager excelDealManager;

    @Autowired
    NumDictionaryManager numDictionaryManager;

    @Autowired
    GenerateService generateService;

    //单次批量缓存的数据量
    private static Integer IMPORT_BATCH_COUNT = 100;

    @Override
    public void exportExcel(Integer type) {
        if (TypeConstants.AOMEN.equals(type)) {
            exportExcel(aoMenManager, PathConstants.AOMEN_EXCEL_PATH, AoMen.class);
        } else {
            exportExcel(xiangGangManager, PathConstants.XIANG_GANG_EXCEL_PATH, XiangGang.class);
        }

    }

    public void exportExcel(BaseManager baseManager, String excelPath, Class<? extends BaseModel> baseModelClass) {
        ExcelWriter excelWriter = null;
        try {
            //1.读取全表数据
            List<DataDTO> dataList = baseManager.selectAllData();
            List<? extends BaseModel> baseModelList = CloneUtils.batchClone(dataList, baseModelClass);

            //创建ExcelWriter（）
            excelWriter = EasyExcel.write(excelPath, AoMen.class).build();
            //创建sheet
            WriteSheet sheet = EasyExcel.writerSheet("表1").build();
            //使用ExcelWriter往sheet中写入数据
            excelWriter.write(baseModelList, sheet);
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }

    @Override
    public void importBigExcel() {
        //1.读取表格
        EasyExcel.read(PathConstants.SECOND_SELECTION_EXCEL_PATH, SecondSelection.class, new ReadListener<SecondSelection>() {

            //单批次缓存的数据量
            private List<SecondSelection> cachedData = new ArrayList<>(IMPORT_BATCH_COUNT);

            /**
             * 每从表格中读取一行数据，都会触发invoke()方法
             * @param secondSelection 读取到的一行数据
             * @param analysisContext
             */
            @Override
            public void invoke(SecondSelection secondSelection, AnalysisContext analysisContext) {
                log.info("读取到数据：{}", secondSelection);
                //先缓存至内存
                cachedData.add(secondSelection);
                //以IMPORT_BATCH_COUNT条数据为一次批量，插入数据库
                if (cachedData.size() >= IMPORT_BATCH_COUNT) {
                    //插入数据库
                    saveData(cachedData);
                    //清理缓存，避免OOM
                    cachedData = new ArrayList<>(IMPORT_BATCH_COUNT);
                }

            }

            /**
             * 表格中所有数据读取完后，都会触发该方法
             * @param analysisContext
             */
            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                //最后一批次数据量若小于IMPORT_BATCH_COUNT，也要插入数据库
                saveData(cachedData);
                log.info("所有数据解析完成！");
            }


        }).sheet().doRead();


    }

    @Override
    public void importLittleExcel() {
        //方法1：使用默认的PageReadListener接口实现
/**        EasyExcel.read(PathConstants.SECOND_SELECTION_EXCEL_PATH, SecondSelection.class, new PageReadListener<SecondSelection>(dataList -> {
 log.info("读取到数据：{}", dataList);
 //插入数据库
 saveData(dataList);
 })).sheet().doRead();
 */
        //方法2：使用自定的监听器
        EasyExcel.read(PathConstants.SECOND_SELECTION_EXCEL_PATH, SecondSelection.class, new ImportExcelListener<SecondSelection, ExcelDealManager>(excelDealManager)).sheet().doRead();
    }

    @Override
    public void secondSelect() {
        /** 1.导入表格 **/
        importLittleExcel();
        /** 2.解析数据 **/
        Set<Integer> safeNums = new HashSet<>();
        Set<Integer> unsafeNums = new HashSet<>();
        // 2.1 风险较小数据
        SecondSelection safeData = excelDealManager.selectSecondSelectionByType(0);
        //使用allAll()时，里面值不能为Null
        safeNums.addAll(NumParseUtils.animalsToNums(safeData.getAnimals())); //生肖
        safeNums.addAll(NumParseUtils.digitsToNums(safeData.getDigits()));   //尾数
        safeNums.addAll(NumParseUtils.bigLittleOddsEvensToNums(safeData.getBiglittleOddeven())); //大小单双
        safeNums.addAll(NumParseUtils.splitNumStr(safeData.getMajorNum()));  //重点号码
        log.info("小风险号码有：{}", safeNums);
        // 2.2 风险较大数据
        SecondSelection unsafeData = excelDealManager.selectSecondSelectionByType(1);
        unsafeNums.addAll(NumParseUtils.animalsToNums(unsafeData.getAnimals())); //生肖
        unsafeNums.addAll(NumParseUtils.digitsToNums(unsafeData.getDigits()));   //尾数
        unsafeNums.addAll(NumParseUtils.bigLittleOddsEvensToNums(unsafeData.getBiglittleOddeven())); //大小单双
        unsafeNums.addAll(NumParseUtils.splitNumStr(unsafeData.getMajorNum()));  //重点号码
        log.info("较大风险号码有：{}", unsafeNums);
        /** 3.二次挑选 **/
        // 3.1 拿到全表初始挑选数据
        List<DataDTO> dataDTOS = aoMenManager.selectAllData();
        // 3.2 二次挑选
        for (DataDTO dataDTO : dataDTOS) {
            if (safeNums.contains(dataDTO.getNum())) {  //处理小风险数据
                calculateSecondSelectValue(dataDTO, safeNums, safeData.getUnitMoney());
            } else if (unsafeNums.contains(dataDTO.getNum())) { //处理大风险数据
                calculateSecondSelectValue(dataDTO, unsafeNums, unsafeData.getUnitMoney());
            }
        }
        // 3.3 重新入库
        aoMenManager.updateBatchData(dataDTOS);

    }

    /**
     * 计算二次挑选金额
     *
     * @param dataDTO
     * @param selectNums
     * @param setMoney
     */
    public void calculateSecondSelectValue(DataDTO dataDTO, Set<Integer> selectNums, Integer setMoney) {
        if (selectNums.contains(dataDTO.getNum())) {
            if (setMoney >= dataDTO.getBuyMoney()) { //如果设定金额大于买入金额：全恰
                dataDTO.setEatMoney(dataDTO.getBuyMoney());
                dataDTO.setExcludeMoney(0);
            } else { //如果设定金额小于买入金额：只恰设定金额
                dataDTO.setEatMoney(setMoney);
                dataDTO.setExcludeMoney(dataDTO.getBuyMoney() - setMoney);
            }
        }
    }

    /**
     * 插入数据库
     *
     * @param dataList
     */
    public void saveData(List<SecondSelection> dataList) {
        int i = excelDealManager.insertBatchSecondSelection(dataList);
        if (i == 0) {
            log.error("本批次插入数据库失败！");
            throw new BizException(RespCodeEnum.INSERT_DATA_FAIL);
        }
        log.info("本批次插入数据库成功！");
    }

    @Override
    public void importCommonExcel(Integer type) {

        if (TypeConstants.AOMEN.equals(type)) {
            aoMenManager.clearTable(); //先清空表
            EasyExcel.read(PathConstants.AOMEN_EXCEL_PATH, AoMen.class, new ImportExcelListener<AoMen, AoMenManager>(aoMenManager)).sheet().doRead();
        } else if (TypeConstants.XiangGang.equals(type)) {
            xiangGangManager.clearTable(); //先清空表
            EasyExcel.read(PathConstants.XIANG_GANG_EXCEL_PATH, XiangGang.class, new ImportExcelListener<XiangGang, XiangGangManager>(xiangGangManager)).sheet().doRead();
        }


    }


    @Override
    public void importNumDictExcel() {

        EasyExcel.read(PathConstants.NUM_DICTIONARY_EXCEL_PATH, NumDictionary.class, new ImportExcelListener<NumDictionary, NumDictionaryManager>(numDictionaryManager)).sheet().doRead();
    }


}
